package com.example.common.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;

import androidx.annotation.Nullable;

import com.example.common.R;

import java.util.ArrayList;
import java.util.List;

public class WarpLinearLayout extends LinearLayout {

    private Type mType;
    private List<WarpLine> mWarpLineGroup;

    public WarpLinearLayout(Context context) {
        super(context);
    }

    public WarpLinearLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, R.style.WarpLinearLayoutDefault);
    }

    public WarpLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mType = new Type(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int width = 0;
        int height = 0;
        int childCount = getChildCount();

        //在调用childView.getMeasured之前先调用measureChildren，用于对子View大小的测量
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        //计算宽度
        switch (widthMode) {
            case MeasureSpec.EXACTLY:   //充满或者精确值
                width = widthSize;
                break;
            case MeasureSpec.AT_MOST:   //自适应
                for (int i = 0; i < getChildCount(); i++) {
                    if (i != 0) {
                        width += mType.horizontal_space;
                    }
                    width += getChildAt(i).getMeasuredWidth();
                    width = Math.min(width, widthSize);
                }
                break;
            case MeasureSpec.UNSPECIFIED:   //想要多大就多大

                for (int i = 0; i <= getChildCount(); i++) {
                    if (i != 0) {
                        width += mType.horizontal_space;
                    }
                    width += getChildAt(i).getMeasuredWidth();
                    width += getPaddingLeft() + getPaddingRight();
                }
                break;
            default:
                width = widthSize;
                break;
        }

        //根据计算出来的宽度，计算所需行数
        WarpLine warpLine = new WarpLine();
        mWarpLineGroup = new ArrayList<>();
        for (int i = 0; i < getChildCount(); i++) {
            if (warpLine.lineWidth + getChildAt(i).getMeasuredWidth() > width) {
                if (warpLine.lineViews.size() == 0) {
                    warpLine.addView(getChildAt(i));
                    mWarpLineGroup.add(warpLine);
                    warpLine = new WarpLine();
                } else {
                    mWarpLineGroup.add(warpLine);
                    warpLine = new WarpLine();
                    warpLine.addView(getChildAt(i));
                }
            } else {
                warpLine.addView(getChildAt(i));
            }
        }

        //添加最后一行
        if (warpLine.lineViews.size() > 0 && !mWarpLineGroup.contains(warpLine)) {
            mWarpLineGroup.add(warpLine);
        }

        //计算高度
        height = getPaddingTop() + getPaddingBottom();
        for (int i = 0; i < mWarpLineGroup.size(); i++) {
            if (i != 0) {
                height += mType.vertical_space;
            }
            height += mWarpLineGroup.get(i).lineHeight;
            switch (heightMode) {
                case MeasureSpec.EXACTLY:
                    height = heightSize;
                    break;
                case MeasureSpec.AT_MOST:
                    break;
                default:
                    break;
            }
        }

        setMeasuredDimension(width, height);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        t = getPaddingTop();
        for (int i = 0; i < mWarpLineGroup.size(); i++) {
            int left = getPaddingLeft();
            WarpLine warpLine = mWarpLineGroup.get(i);
            int surplusWidth = getMeasuredWidth() - warpLine.lineWidth;
            for (int j = 0; j < warpLine.lineViews.size(); j++) {
                View view = warpLine.lineViews.get(j);
                if (mType.isFull) {
                    view.layout(left, t, view.getMeasuredWidth() + left + surplusWidth / warpLine.lineViews.size(), t + view.getMeasuredHeight());
                    left += view.getMeasuredWidth() + mType.horizontal_space + surplusWidth / warpLine.lineViews.size();
                } else {
                    switch (mType.gravity) {
                        case Type.LEFT:
                            view.layout(left, t, left + view.getMeasuredWidth(), t + view.getMeasuredHeight());
                            break;
                        case Type.RIGHT:
                            view.layout(surplusWidth + left, t, left + surplusWidth + view.getMeasuredWidth(), t + view.getMeasuredHeight());
                            break;
                        case Type.CENTER:
                            view.layout(left + surplusWidth / 2, t, left + surplusWidth / 2 + view.getMeasuredWidth(), t + view.getMeasuredHeight());
                            break;
                    }
                    left += view.getMeasuredWidth() + mType.horizontal_space;
                }
            }
            t += warpLine.lineHeight + mType.vertical_space;
        }
    }

    /**
     *
     */
    private final class WarpLine {
        /**
         * 每行View的集合
         */
        private List<View> lineViews = new ArrayList<>();

        /**
         * 当前行中需要占据的宽度
         */
        private int lineWidth = getPaddingLeft() + getPaddingRight();

        /**
         * 当前行中需要占据的最大高度
         */
        private int lineHeight = 0;

        /**
         * 添加view
         *
         * @param view
         */
        private void addView(View view) {
            if (lineViews.size() != 0) {
                lineWidth += mType.horizontal_space;
            }
            lineWidth += view.getMeasuredWidth();
            lineHeight = Math.max(lineHeight, view.getMeasuredHeight());
            lineViews.add(view);
        }
    }

    /**
     * 样式属性
     */
    private final static class Type {

        /**
         * 对齐方式属性
         */
        public static final int LEFT = 0;
        public static final int RIGHT = 1;
        public static final int CENTER = 2;

        /**
         * 对齐方式 left 0,right 1,center 2
         */
        private int gravity;

        /**
         * 水平间距 px
         */
        private float horizontal_space;

        /**
         * 垂直间距
         */
        private float vertical_space;

        /**
         * 自动填满
         */
        private boolean isFull;

        Type(Context context, AttributeSet attrs) {
            if (attrs == null || context == null) {
                return;
            }
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.WarpLinearLayout);
            gravity = typedArray.getInt(R.styleable.WarpLinearLayout_gravity, gravity);
            horizontal_space = typedArray.getDimension(R.styleable.WarpLinearLayout_horizontal_space, horizontal_space);
            vertical_space = typedArray.getDimension(R.styleable.WarpLinearLayout_vertical_space, vertical_space);
            isFull = typedArray.getBoolean(R.styleable.WarpLinearLayout_isFull, isFull);
        }

        public int getGravity() {
            return gravity;
        }

        public void setGravity(int gravity) {
            this.gravity = gravity;
        }

        public float getHorizontal_space() {
            return horizontal_space;
        }

        public void setHorizontal_space(float horizontal_space) {
            this.horizontal_space = horizontal_space;
        }

        public float getVertical_space() {
            return vertical_space;
        }

        public void setVertical_space(float vertical_space) {
            this.vertical_space = vertical_space;
        }

        public boolean isFull() {
            return isFull;
        }

        public void setFull(boolean full) {
            isFull = full;
        }
    }
}
